import java.util.Arrays;
import java.util.LinkedList;
import java.util.Queue;

public final class GoalAgent {
	
	public enum GoalType {
		ENEMY_HILL,
	};
	
	private static final float REDUCTION_RATE = 0.99f;
	private static final int ENEMY_HILL = 2 << 20;
	private static final int[] HILL_COEFF = {
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 0)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 1)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 2)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 3)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 4)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 5)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 6)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 7)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 8)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 9)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 10)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 11)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 12)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 13)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 14)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 15)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 16)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 17)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 18)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 19)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 20)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 21)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 22)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 23)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 24)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 25)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 26)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 27)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 28)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 29)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 30)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 31)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 32)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 33)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 34)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 35)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 36)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 37)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 38)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 39)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 40)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 41)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 42)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 43)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 44)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 45)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 46)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 47)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 48)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 49)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 50)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 51)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 52)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 53)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 54)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 55)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 56)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 57)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 58)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 59)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 60)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 61)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 62)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 63)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 64)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 65)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 66)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 67)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 68)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 69)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 70)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 71)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 72)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 73)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 74)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 75)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 76)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 77)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 78)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 79)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 80)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 81)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 82)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 83)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 84)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 85)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 86)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 87)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 88)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 89)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 90)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 91)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 92)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 93)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 94)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 95)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 96)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 97)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 98)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 99)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 100)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 101)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 102)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 103)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 104)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 105)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 106)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 107)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 108)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 109)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 110)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 111)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 112)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 113)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 114)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 115)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 116)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 117)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 118)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 119)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 120)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 121)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 122)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 123)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 124)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 125)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 126)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 127)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 128)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 129)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 130)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 131)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 132)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 133)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 134)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 135)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 136)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 137)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 138)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 139)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 140)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 141)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 142)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 143)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 144)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 145)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 146)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 147)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 148)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 149)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 150)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 151)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 152)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 153)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 154)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 155)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 156)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 157)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 158)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 159)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 160)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 161)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 162)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 163)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 164)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 165)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 166)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 167)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 168)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 169)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 170)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 171)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 172)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 173)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 174)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 175)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 176)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 177)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 178)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 179)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 180)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 181)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 182)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 183)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 184)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 185)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 186)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 187)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 188)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 189)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 190)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 191)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 192)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 193)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 194)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 195)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 196)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 197)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 198)),
			(int) (ENEMY_HILL * Math.pow(REDUCTION_RATE, 199)),
	};
	
	int rows;
	int cols;
	int goalR;
	int goalC;
	int[][] map = null;
	boolean[][] processed = null;
	Tile[][] tiles = null;
	Ants ants;
	private int[] coeffType;

	public GoalAgent(Ants ants, int rows, int cols) {
		this.ants = ants;
		this.rows = rows;
		this.cols = cols;
		map = new int[rows][cols];
		processed = new boolean[rows][cols];

		reset();
	}

	public void setGoal(int row, int col) {
		this.goalR = row;
		this.goalC = col;
	}

	public void setTiles(Tile[][] tiles) {
		this.tiles = tiles;
	}

	public void reset() {
		for (int i = 0; i < map.length; i++) {
			Arrays.fill(map[i], 0);
			Arrays.fill(processed[i], false);
		}
		tiles = null;
		goalR = 0;
		goalC = 0;
		coeffType = null;
	}

	public void createDiffionMap() {
		
		for (int i = 0; i < map.length; i++) {
			Arrays.fill(processed[i], false);
			Arrays.fill(map[i], 0);
		}

		int startR = goalR;
		int startC = goalC;
		int currentCooefIndex = 0;
		Tile current = tiles[startR][startC];

		Queue<Tile> openList = new LinkedList<Tile>();
		Queue<Tile> closeList = new LinkedList<Tile>();
		Queue<Tile> tempList;

		// Add the starting point into open list.
		processed[current.getRow()][current.getCol()] = true;
		openList.add(current);
		map[current.getRow()][current.getCol()] = coeffType[currentCooefIndex];

		while (!openList.isEmpty() && currentCooefIndex < coeffType.length) {

			while (!openList.isEmpty()) {
				current = openList.poll();

				for (final Aim direction : Aim.values()) {

					final Tile tile = getTile(current, direction);
					if (!processed[tile.getRow()][tile.getCol()]
							&& ants.getIlk(tile).isPassable()) {
						closeList.add(tile);
						map[current.getRow()][current.getCol()] = coeffType[currentCooefIndex];
						processed[tile.getRow()][tile.getCol()] = true;
					}
				}
			}
			currentCooefIndex++;
			tempList = openList;
			openList = closeList;
			closeList = tempList;
		}
		
//		debug();
	}

	private Tile getTile(Tile tile, Aim direction) {
		int row = (tile.getRow() + direction.getRowDelta()) % rows;
		if (row < 0) {
			row += rows;
		}
		int col = (tile.getCol() + direction.getColDelta()) % cols;
		if (col < 0) {
			col += cols;
		}

		return tiles[row][col];
	}

	private void debug() {
		StringBuilder strB = new StringBuilder();
		for (int i = 0; i < map.length; i++) {
			strB.append(String.format("%7d ", i));
		}
		MyBot.debug.log(Debug.DEBUG_ATTACK_DEBUG,
				String.format(" col : %s", strB));

		for (int i = 0; i < map.length; i++) {
			String str = "";
			for (int j = 0; j < map[i].length; j++) {
				str += String.format("%7d ", map[i][j]);
			}
			MyBot.debug.log(Debug.DEBUG_ATTACK_DEBUG,
					String.format(" %7d : %s", i, str));
		}
	}

	public void setType(GoalType enemyHill) {
		switch (enemyHill) {
		case ENEMY_HILL:
			coeffType = HILL_COEFF;
			break;
		}
	}
}
